package indi.jp.project.core.filter;

import indi.jp.project.core.util.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

public class AuthenticationFilter extends BasicAuthenticationFilter {

    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    /**
     * 在拦截器中获取token并解析，拿到用户信息，放置到SecurityContextHolder，这样便完成了springsecurity和jwt的整合。
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
//        System.out.println("| -------------------- AuthenticationFilter -------------------- |");
        String token = request.getHeader(JwtUtil.HEADER);
        // 先判断令牌是否为空，是否是规定格式
        if (token != null && token.startsWith(JwtUtil.HEADER_PREFIX)) {
            token = token.replace(JwtUtil.HEADER_PREFIX, "");
            try {
                Claims claims = JwtUtil.getTokenBody(token);
                UsernamePasswordAuthenticationToken authentication = getAuthentication(claims);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                chain.doFilter(request, response);
            } catch (ExpiredJwtException e) {
                response.setStatus(401);
            }
        } else {
            chain.doFilter(request, response);
        }
    }

    @SuppressWarnings("unchecked")
    private UsernamePasswordAuthenticationToken getAuthentication(Claims claims) {
        String user = claims.getSubject();
        List<String> authorities = claims.get("authority", List.class);
        List<SimpleGrantedAuthority> auth = authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
        if (user != null) {
            return new UsernamePasswordAuthenticationToken(user, null, auth);
        }
        return null;
    }
}
